import { cloneDeep, get, isBoolean, isFunction, merge } from 'lodash';
import { BasicTableProps, Recordable } from '../types';
import { FETCH_SETTING, PAGE_SIZE, ROW_KEY } from '../const';
import { buildUUID } from '../utils/uuid';
import { ComputedRef, Ref, ref, watchEffect, unref, watch, computed, onMounted, nextTick } from 'vue';

interface ActionType {
  getMetaInfo: ComputedRef<Recordable>;
  getSearchParams: ComputedRef<Recordable>;
  setTotal: (value: number) => void;
  setCurrentPage: (value: number) => void;
  clearSelectedRowKeys: () => void;
  tableData: Ref<Recordable[]>;
}

export default function useDataSource(
  propsRef: ComputedRef<BasicTableProps>,
  {
    getMetaInfo,
    getSearchParams,
    setTotal,
    setCurrentPage,
    // clearSelectedRowKeys,
    tableData,
  }: ActionType,
  emit: ReturnType<typeof defineEmits>,
) {
  const loading = ref(false);
  // 排序条件
  const sortInfo = ref<Recordable | null>();
  const dataRef = ref<Recordable[]>([]);
  const rawDataSourceRef = ref<Recordable>({});

  watchEffect(() => {
    tableData.value = unref(dataRef);
  });

  watch(
    () => unref(propsRef).data,
    () => {
      const { data, api } = unref(propsRef);
      !api && data && (dataRef.value = data);
    },
    {
      immediate: true,
    },
  );
  const getAutoCreateKey = computed(() => {
    return unref(propsRef).autoCreateKey && !unref(propsRef).rowKey;
  });
  const getDataRef = computed(() => {
    const dataSource = unref(dataRef);
    if (!dataSource || dataSource.length === 0) {
      return unref(dataRef);
    }
    if (unref(getAutoCreateKey)) {
      const firstItem = dataSource[0];
      const lastItem = dataSource[dataSource.length - 1];

      if (firstItem && lastItem) {
        if (!firstItem[ROW_KEY] || !lastItem[ROW_KEY]) {
          const data = cloneDeep(unref(dataRef));
          data.forEach((item) => {
            if (!item[ROW_KEY]) {
              item[ROW_KEY] = buildUUID();
            }
            if (item.children && item.children.length) {
              setTableKey(item.children);
            }
          });
          dataRef.value = data;
        }
      }
    }
    return unref(dataRef);
  });

  const getRowKey = computed(() => {
    const { rowKey } = unref(propsRef);
    return unref(getAutoCreateKey) ? ROW_KEY : rowKey;
  });
  function setTableKey(items: any[]) {
    if (!items || !Array.isArray(items)) return;
    items.forEach((item) => {
      if (!item[ROW_KEY]) {
        item[ROW_KEY] = buildUUID();
      }
      if (item.children && item.children.length) {
        setTableKey(item.children);
      }
    });
  }

  async function fetch(opt?: any) {
    const { api, searchInfo, defaultSort, fetchSetting, beforeFetch, afterFetch, pagination } =
      unref(propsRef);
    if (!api || !isFunction(api)) return;
    try {
      loading.value = true;
      const { pageField, sizeField, listField, totalField } = Object.assign(
        {},
        FETCH_SETTING,
        fetchSetting,
      );
      // 分页数据
      let pageParams: Recordable = {};
      const { currentPage = 1, pageSize = PAGE_SIZE } = unref(getMetaInfo);

      if (isBoolean(pagination) && !pagination) {
        pageParams = {};
      } else {
        pageParams[pageField] = (opt && opt.page) || currentPage;
        pageParams[sizeField] = pageSize;
      }

      let params: Recordable = merge(
        // 分页参数
        pageParams,
        // 搜索参数
        unref(getSearchParams),
        // 特定搜索参数
        searchInfo,
        // 排序参数
        getSortInfo(),
        // 指定搜索参数
        opt?.searchInfo ?? {},
        opt?.sortInfo ?? {},
        opt?.filterInfo ?? {},
      );

      if (beforeFetch && isFunction(beforeFetch)) {
        params = (await beforeFetch(params)) || params;
      }

      const res = await api(params);
      rawDataSourceRef.value = res;

      const isArrayResult = Array.isArray(res);

      let resultItems: Recordable[] = isArrayResult ? res : get(res, listField);
      const resultTotal: number = isArrayResult ? res.length : get(res, totalField);

      if (Number(resultTotal)) {
        const currentTotalPage = Math.ceil(resultTotal / pageSize);
        if (currentPage > currentTotalPage) {
          setCurrentPage(currentTotalPage);
          return await fetch(opt);
        }
      }

      if (afterFetch && isFunction(afterFetch)) {
        resultItems = (await afterFetch(resultItems)) || resultItems;
      }
      dataRef.value = resultItems;

      setTotal(resultTotal || 0);

      if (opt && opt.page) {
        setCurrentPage(opt.page || 1);
      }

      emit('fetch-success', {
        items: unref(resultItems),
        total: resultTotal,
      });
      return resultItems;
    } catch (error) {
      emit('fetch-error', error);
      dataRef.value = [];
      setTotal(0);
    } finally {
      loading.value = false;
    }
  }

  function setTableData<T = Recordable>(values: T[]) {
    dataRef.value = values as Recordable[];
  }

  function getData<T = Recordable>() {
    return unref(getDataRef) as T[];
  }

  async function reload(opt?: any) {
    return await fetch(opt);
  }
  function setSortInfo(data: Recordable) {
    if (data.order) {
      sortInfo.value = data;
    } else {
      sortInfo.value = null;
    }
    reload();
  }

  function getSortInfo() {
    try {
      const data = unref(sortInfo) || unref(propsRef).defaultSort || {};
      if (data && data.order) {
        return {
          order: data.prop,
          sort: data.order.replace('ending', ''),
        };
      } else {
        return {};
      }
    } catch (error) {
      console.log(error);
    }
  }

  function handleTableChange() {}

  onMounted(() => {
    setTimeout(() => {
      if (unref(propsRef).immediate !== false) {
        fetch();
      }
    }, 16);
  });

  return {
    loading,
    getDataRef,
    getData,
    setTableData,
    setSortInfo,
    getRowKey,
    fetch,
    reload,
    handleTableChange,
  };
}
